from interface.widget import Page, scale, Container, scale_factor
from tkinter import ttk
from utils import memory
from utils.schedule import Scheduler, PCB, clock
import tkinter


class SchedulePage(Page):

    def content(self, master):
        memory.app.tk.title('进程调度')

        button_box = ttk.Frame(master)
        button_box.place(**scale(x=30, y=20, relwidth=1, width=-60, height=30))

        button_next = ttk.Button(button_box, text='下一个时间片')
        button_next.place(**scale(x=100, y=0, width=90, relheight=1))

        button_sleep_progress = ttk.Button(button_box, text='阻塞当前进程')
        button_sleep_progress.place(**scale(x=200, y=0, width=90, relheight=1))

        button_add_progress = ttk.Button(button_box, text='添加进程')
        button_add_progress.place(**scale(x=300, y=0, width=90, relheight=1))

        table = ttk.Frame(master)
        table.place(**scale(x=30, y=50, relwidth=1, width=-60, relheight=1, height=-50))

        tick_label = ttk.Label(table, text='当前时间片：')
        tick_label.place(**scale(x=0, y=0, width=90, height=30))

        tick_value = ttk.Label(table, text=0)
        tick_value.place(**scale(x=100, y=0, width=100, height=30))

        queue_container = ttk.Frame(table)
        queue_container.place(**scale(x=0, y=30, relwidth=1, relheight=1, height=-30))

        label_ready = ttk.Label(queue_container, text='就绪队列 (Ready)')
        label_ready.place(**scale(relx=0, rely=0, relwidth=0.25, height=30))

        label_execute = ttk.Label(queue_container, text='执行队列 (Execute)')
        label_execute.place(**scale(relx=0.25, rely=0, relwidth=0.25, height=30))

        label_wait = ttk.Label(queue_container, text='等待队列 (Wait)')
        label_wait.place(**scale(relx=0.5, rely=0, relwidth=0.25, height=30))

        label_finish = ttk.Label(queue_container, text='完成队列 (Finish)')
        label_finish.place(**scale(relx=0.75, rely=0, relwidth=0.25, height=30))

        ready_queue = ProgressQueueContainer(queue_container)
        ready_queue.relx = 0
        ready_queue.y = 30
        ready_queue.relwidth = 0.25
        ready_queue.display()

        execute_queue = ProgressQueueContainer(queue_container)
        execute_queue.relx = 0.25
        execute_queue.y = 30
        execute_queue.relwidth = 0.25
        execute_queue.display()

        wait_queue = ProgressQueueContainer(queue_container)
        wait_queue.relx = 0.5
        wait_queue.y = 30
        wait_queue.relwidth = 0.25
        wait_queue.display()

        finish_queue = ProgressQueueContainer(queue_container)
        finish_queue.relx = 0.75
        finish_queue.y = 30
        finish_queue.relwidth = 0.25
        finish_queue.display()

        sch = Scheduler()
        clock.on_tickle = sch.schedule
        clock.reset_tick()

        sch.new_progress(PCB('init', -100000, 100000))

        clock.tickle()

        def str_pcb(pcb):
            assert isinstance(pcb, PCB)
            return '{}[{}]({},{}/{})'.format(pcb.name, pcb.prio, pcb.tick_come, pcb.tick_pass, pcb.tick_claim)

        def str_pcb_sleep(pcb):
            assert isinstance(pcb, PCB)
            return '{}[{}]({},{}/{}, {})'.format(pcb.name, pcb.prio, pcb.tick_come,
                                                 pcb.tick_pass, pcb.tick_claim, pcb.tick_sleep)

        def scheduler2queue(_sch):
            return {
                'rs': [str_pcb(p) for p in _sch.rs],
                'es': [str_pcb(p) for p in _sch.es],
                'ws': [str_pcb_sleep(p) for p in _sch.ws],
                'fs': [str_pcb(p) for p in _sch.fs]
            }

        def update_queue_views():
            snapshot = scheduler2queue(sch)
            ready_queue.update(snapshot['rs'])
            execute_queue.update(snapshot['es'])
            wait_queue.update(snapshot['ws'])
            finish_queue.update(snapshot['fs'])
            tick_value['text'] = clock.get_tick()

        update_queue_views()

        def next_tick():
            clock.tickle()
            update_queue_views()

        button_next['command'] = next_tick

        def add_progress(name, prio, claim):
            sch.new_progress(PCB(name=name, prio=prio, tick_claim=claim))
            update_queue_views()

        def open_add_progress_messagebox():
            window = tkinter.Tk()
            window.title('添加进程')
            window.geometry('{}x{}'.format(int(200 * scale_factor), int(230 * scale_factor)))
            name_label = ttk.Label(window, text='请输入进程名字')
            name_label.place(**scale(x=0, y=0, relwidth=1, height=30))
            name_entry = ttk.Entry(window)
            name_entry.place(**scale(x=0, y=30, relwidth=1, height=25))
            prio_label = ttk.Label(window, text='请输入进程优先级(整数)')
            prio_label.place(**scale(x=0, y=60, relwidth=1, height=30))
            prio_entry = ttk.Entry(window)
            prio_entry.place(**scale(x=0, y=90, relwidth=1, height=25))
            claim_label = ttk.Label(window, text='请输入进程声明完成时间(整数)')
            claim_label.place(**scale(x=0, y=120, relwidth=1, height=30))
            claim_entry = ttk.Entry(window)
            claim_entry.place(**scale(x=0, y=150, relwidth=1, height=25))

            def add_button_method():
                name = name_entry.get()
                prio = int(prio_entry.get())
                claim = int(claim_entry.get())
                window.quit()
                window.destroy()
                add_progress(name, prio, claim)

            add_button = ttk.Button(window, text='添加', command=add_button_method)
            add_button.place(**scale(relx=0.5, x=-30, y=190, width=60, height=30))

            window.mainloop()

        button_add_progress['command'] = open_add_progress_messagebox

        def sleep_progress(tick):
            sch.sleep_progress(tick)
            update_queue_views()

        def open_sleep_progress_messagebox():
            window = tkinter.Tk()
            window.title('阻塞进程')
            window.geometry('{}x{}'.format(int(200 * scale_factor), int(105 * scale_factor)))
            label = ttk.Label(window, text='请输入睡眠时间片(整数)')
            label.place(**scale(x=0, y=0, relwidth=1, height=30))
            entry = ttk.Entry(window)
            entry.place(**scale(x=0, y=30, relwidth=1, height=25))

            def add_button_method():
                tick = int(entry.get())
                window.quit()
                window.destroy()
                sleep_progress(tick)

            add_button = ttk.Button(window, text='阻塞', command=add_button_method)
            add_button.place(**scale(relx=0.5, x=-30, y=65, width=60, height=30))

            window.mainloop()

        button_sleep_progress['command'] = open_sleep_progress_messagebox


class ProgressQueueContainer(Container):

    def __init__(self, master):
        Container.__init__(self, master)
        self.widget_list = []

    def update(self, text_list):
        master = self.tkw
        while len(self.widget_list) > 0:
            self.widget_list.pop().destroy()
        for text in text_list:
            label = ttk.Label(master, text=text)
            label.place(**scale(relx=0, y=30 * len(self.widget_list), relwidth=1, height=30))
            self.widget_list.append(label)
        master.update()
        master.place(**scale(height=self.max_children_y()))
